home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
- Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior permission.
-
- STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
- FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
- /*
- ** dl_ldzfilep - Load ZMAGIC file using mmap
- */
-
- #define _auxtemp _auxtemp1 /* A bug in ldfcn.h */
-
- #include <stdio.h>
- #include <filehdr.h>
- #include <syms.h>
- #include <ar.h>
- #include <scnhdr.h>
- #include <ldfcn.h>
- #include <nlist.h>
- #include <assert.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/fcntl.h>
- #include <sys/mman.h>
-
- #include "dl.h"
-
- #ifdef DEBUG
- #define D(x) (x)
- #else
- #define D(x)
- #endif /* DEBUG */
-
- /*
- ** dl_ldzfilep loads a ZMAGIC file into memory using mmap() calls (thereby
- ** making at least the text segment of the binary demand-paged form the
- ** original load image).
- **
- ** Due to some ideosyncracies in the way mmap() work we have to collect all
- ** BSS and DATA segments and map them together. The current code only works
- ** well if the following two things are true:
- ** - All data segments (rdata, data, sdata, etc) are contiguous, and the
- ** sections in the load file are sorted on address and their data is
- ** stored contiguous
- ** - All bss segment section descriptors are contiguous, their sections are
- ** sorted on address and they follow all the data segments.
- **
- ** As far as I can tell this is true for all normal binaries.
- ** Unexpected things may happen if this is untrue, since the routine does
- ** only some very cursory checks to verify these hypotheses.
- */
-
- extern int getpagesize (void);
- extern int open (const char *, int, ...);
- extern int close (int);
- extern off_t lseek (int, off_t, int);
- extern int read (int, void *, unsigned int);
-
- int
- dl_ldzfilep(struct ldfile *ldptr, char *fn)
- {
- int i;
- int nsect; /* Number of sections */
- struct scnhdr shdr; /* Current section header */
- int fd; /* load file fd (for mmap) */
- int nullfd; /* /dev/zero fd (for bss mmap) */
- unsigned long addr, eaddr, off; /* rounded section address/file-off */
- unsigned long pagesize, pagemask; /* mmu parameters */
- void *rv; /* mmap return value */
- unsigned long lodata, hidata, lobss, hibss; /* Data/bss location */
- unsigned long offdata;
- int hasdata, hasbss;
-
- /*
- ** First some initializations.
- */
- pagesize = getpagesize();
- pagemask = pagesize-1;
- assert ( (pagesize|pagemask) == pagesize+pagemask);
- fd = open(fn,O_RDONLY);
- if(fd < 0) {
- dl_error("Could not open fd for mmap on %s", fn);
- return 0;
- }
- if ( (nullfd = open("/dev/zero", 0)) < 0) {
- dl_error(0, "/dev/zero");
- close(fd);
- return 0;
- }
- nsect = HEADER(ldptr).f_nscns;
- D(printf("loadfile: %d sections\n", nsect));
- D(printf("loadfile: version stamp=%d, 0x%x\n", SYMHEADER(ldptr).vstamp,
- SYMHEADER(ldptr).vstamp));
- /*
- ** Now loop over the sections, and load them if needed.
- */
- lodata = lobss = 0xffffffff;
- hidata = hibss = 0;
- hasdata = hasbss = 0;
- offdata = 0xffffffff;
- for ( i=1; i<nsect+1; i++ ) {
- if ( ldshread(ldptr, i, &shdr) == FAILURE ) {
- dl_error("Cannot read section header %d", (char *)i);
- close(nullfd); close(fd);
- return 0;
- }
- D(printf("loadfile: section %d=%s, 0x%x:0x%x@0x%x type 0x%x\n", i,
- shdr.s_name, shdr.s_vaddr, shdr.s_size, shdr.s_scnptr, shdr.s_flags));
- if ( shdr.s_scnptr &&
- (shdr.s_vaddr&pagemask) != (shdr.s_scnptr&pagemask) ) {
- /* Incorrectly aligned segment */
- dl_error("Incorrect alignment in section %d", (char *)i);
- close(nullfd); close(fd);
- return 0;
- }
- addr = shdr.s_vaddr & ~pagemask;
- eaddr = shdr.s_vaddr + shdr.s_size;
- off = shdr.s_scnptr & ~pagemask;
- D(printf("Addr %x, off %x\n", addr, off));
- /*
- ** We would like to use the lower 4 bits in s_flags here to decide
- ** what to do with the segment (allocate/load), but they don't seem
- ** to be set correctly. So, we have to fiddle.
- */
- switch(shdr.s_flags) {
- case STYP_TEXT:
- if ( !dl_setrange(addr, eaddr) )
- return 0;
- rv = mmap((void *)addr, eaddr - addr, PROT_READ|PROT_EXECUTE,
- MAP_SHARED|MAP_FIXED, fd, off);
- D(printf("rv=%x addr=%x\n", rv, addr));
- if ( addr != (unsigned long)rv ) {
- dl_error(0, "mmap(.text)");
- close(nullfd); close(fd);
- return 0;
- }
- break;
- case STYP_DATA:
- case STYP_RDATA:
- case STYP_SDATA:
- case STYP_LIT8:
- case STYP_LIT4:
- /* Could do many more sanity checks here */
- if ( addr < lodata) {
- if ( lodata != 0xffffffff ) {
- dl_error("Data segments incorrectly ordered", 0);
- close(nullfd); close(fd);
- return 0;
- }
- lodata = addr;
- }
- if ( eaddr > hidata )
- hidata = eaddr;
- if ( off < offdata )
- offdata = off;
- hasdata = 1;
- break;
- case STYP_BSS:
- case STYP_SBSS:
- if ( addr < lobss )
- lobss = addr;
- if ( eaddr > hibss )
- hibss = eaddr;
- hasbss = 1;
- break;
- case _STYP_RESOURCE:
- break;
- default:
- dl_error("Unknown section type 0x%x", (char *)shdr.s_flags);
- close(nullfd); close(fd);
- return 0;
- }
- }
- /*
- ** Now map in all of data space, if there is any.
- ** It seems we can't map bss space into the same region, so
- ** we map all of it private, and read it in ourselves.
- */
- if ( hasdata || hasbss ) {
- if ( hasdata && hasbss && hibss < hidata ) {
- /* Segments in the wrong order */
- dl_error(0, "data/bss segments in wrong order");
- return 0;
- }
- if ( !hasdata )
- lodata = hidata = lobss;
- if ( !hasbss )
- lobss = hibss = hidata;
- D(printf("Data mmap(0x%x, 0x%x, ...)\n", lodata, hibss-lodata));
- if( !dl_setrange(lodata, hibss) )
- return 0;
- rv = mmap((void *)lodata, hibss-lodata, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_FIXED, nullfd, 0);
- if ( (unsigned long)rv != lodata ) {
- D(printf("mmap(data)=0x%x, not 0x%x\n", rv, lodata));
- dl_error(0, "mmap(data segments)");
- close(nullfd); close(fd);
- return 0;
- }
- if ( hasdata ) {
- D(printf("Data read 0x%x..0x%x from 0x%x\n", lodata, hidata, offdata));
- lseek(fd, offdata, 0);
- if ( read(fd, (void *)lodata, hidata-lodata) != hidata-lodata ) {
- dl_error(0, "Could not read data segments");
- return 0;
- }
- }
- }
- close(nullfd);
- return 1;
- }
-